package timing;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.concurrent.TimeUnit;

import javax.swing.JLabel;

public class Zadanie extends JLabel implements ActionListener, Serializable {

	/*
	 * S1 - pierwszy system liczenia czasu s1CzasTrwania = z licznika s1CzasPauz
	 * = z dat spauzowania i odpauzowania s1CzasTotal = s1CzasTrwania +
	 * s1CzasPauz
	 * 
	 * S2 - drugi, kontrolny, system liczenia czasu s2CzasTrwania = s2CzasTotal
	 * - s2CzasPauz s2CzasPauz = z dat spauzowania i odpauzowania s2CzasTotal =
	 * z dat startu i endu zadania
	 * 
	 * 
	 * S3 - trzeci, kontrolny, system liczenia czasu s3CzasTrwania = s2CzasTotal
	 * - s2CzasPauz s3CzasPauz = BRAK, chyba że dodamy jako parametr s3CzasTotal
	 * = z dat startu i endu zadania
	 */

	/* STATIKI */
	static int autoCounter = 1;
	static Zadanie aktualneZadanie;
	static ArrayList<Zadanie> wszystkieZadania = new ArrayList<Zadanie>();
	static ArrayList daty = new ArrayList<>();

	static ArrayList opisy = new ArrayList<>();

	/* ZADANIE OPIS */
	int iDZadania;
	String dataZadania;
	String opis = "______";
	int ilePauzZadania = 0;
	String ilePauzZadaniaS = "";

	String czasRozpoczecia = "__:__:__";
	String czasZakonczenia = "__:__:__";

	Date dataRozpoczecia; // potrzebne do wyliczania ręcznego
	Date dataZakonczenia; // potrzebne do wyliczania czasu trwania z dat

	long s1CzasTrwaniaFaktyczny = 0;
	String s1CzasTrwaniaFaktycznyS = "00:00:00";
	long s1CzasTotal;
	String s1CzasTotalS = "";
	long s1CzasPauz = 0;
	String s1CzasPauzS = "";

	long s2CzasTotal;
	String s2CzasTotalS = "";

	long s3CzasTotal;
	String s3CzasTotalS = "00:00:00";

	String przebiegZadaniaMeldunek = ""; // meldunki z bieżacych operacji,
											// wyświetlane w konsoli, a
	// dzięki temu stringowi dodawane także w oknie

	// static double redmineDzienny = 0;

	/* TIMER */
	private javax.swing.Timer timer = new javax.swing.Timer(100, this);
	boolean running = false;
	private long initTimeLicznika = System.currentTimeMillis();
	private long startTimeLicznika;
	private long pauseTimeLicznika;
	long licznikBiezacy;

	String licznikFormatMilisekund;
	String licznikFormatZegarowy;
	String terminSpauzowania;
	String terminOdpauzowania;
	long tempCzasPauz;
	Date dataSpauzowania; // wyliczanie pauzy
	Date dataOdpauzowania; // wyliczanie pauzy

	/* POMOCNICZE */
	static DateFormat formatyyyyMMdd = new SimpleDateFormat("yyyy/MM/dd");
	static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
	static SimpleDateFormat longDateFormat = new SimpleDateFormat("HH:mm:ss");
	static String aktualnaData = null;

	// long pauzaOd; // tylko wyświetlanie

	long nanoStart;

	/* KONSTRUKTOR */
	public Zadanie() {
		licznikBiezacy = System.currentTimeMillis() - initTimeLicznika;
		licznikFormatMilisekund = "" + (System.currentTimeMillis() - initTimeLicznika);
		licznikFormatZegarowy = formatZDziesiatymiSekundy(System.currentTimeMillis() - initTimeLicznika);
		setText(licznikFormatZegarowy + "  |  " + licznikFormatMilisekund);
	}

	public static Zadanie utworzNoweZadanie() {
		aktualneZadanie = new Zadanie();
		aktualneZadanie.iDZadania = autoCounter++;
		aktualneZadanie.dataZadania = formatyyyyMMdd.format(new Date());
		wszystkieZadania.add(aktualneZadanie);
		if (!daty.contains(aktualneZadanie.dataZadania)) {
			daty.add(aktualneZadanie.dataZadania);
		}

		return aktualneZadanie;
	}

	public static void zamknijBiezace() {
		aktualneZadanie = null;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		licznikBiezacy = System.currentTimeMillis() - startTimeLicznika;
		licznikFormatMilisekund = "" + (System.currentTimeMillis() - startTimeLicznika);
		licznikFormatZegarowy = formatZDziesiatymiSekundy(System.currentTimeMillis() - startTimeLicznika);
		setText(licznikFormatZegarowy + "  |  " + licznikFormatMilisekund);
	}

	public void startCounter() {
		utworzNoweZadanie();
		if (running == false) {
			startTimeLicznika = System.currentTimeMillis();

			nanoStart = System.nanoTime();

			Timestamp timestamp = new Timestamp(System.currentTimeMillis());
			aktualneZadanie.dataRozpoczecia = new Date(timestamp.getTime());
			aktualneZadanie.czasRozpoczecia = simpleDateFormat.format(timestamp);

			// System.out.println("- Otwarto zadanie. Czas rozpoczęcia zadania: "
			// + longDateFormat.format(aktualneZadanie.dataRozpoczecia));

			przebiegZadaniaMeldunek += "- XOtwarto zadanie " + aktualneZadanie.iDZadania + ". Czas rozpoczęcia zadania: [" + aktualneZadanie.czasRozpoczecia + "]\n";

		} else {
			startTimeLicznika = System.currentTimeMillis() - (pauseTimeLicznika - startTimeLicznika);
		}
		timer.start();
		running = true;
	}

	

	public void nadajOpis(String text) {
		this.opis = text;
		przebiegZadaniaMeldunek += "- XDodano opis: " + text + "\n";
		if (!opisy.contains(text)) {
			opisy.add(text);
		}
		//zaktualizujSumeDlaOpisu();
	}
	
	public void stopCounter() {
		timer.stop();
		long ile = System.nanoTime();
		running = false;

		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
		aktualneZadanie.dataZakonczenia = new Date(timestamp.getTime());
		// System.out.println("s2 - czas końca zadania: " +
		// longDateFormat.format(aktualneZadanie.dataZakonczenia));

		long odDo = (ile - nanoStart) / 1000000;
		// System.out.println("System2 czas total:  " + odDo);

		String licznik = getText();
		// System.out.println(licznik);

		aktualneZadanie.s1CzasTrwaniaFaktyczny = licznikBiezacy;


		aktualneZadanie.s1CzasTrwaniaFaktycznyS = formatZSekundami(aktualneZadanie.s1CzasTrwaniaFaktyczny) + ", " + aktualneZadanie.s1CzasTrwaniaFaktyczny;
		aktualneZadanie.czasZakonczenia = simpleDateFormat.format(timestamp);


		przebiegZadaniaMeldunek += "- XZamknięto zadanie " + aktualneZadanie.iDZadania + ". Czas zakończenia zadania: [" + aktualneZadanie.czasZakonczenia + "]\n";
		przebiegZadaniaMeldunek += "- XPodsumowanie czasu" + "\n";
		przebiegZadaniaMeldunek += "  XCzas trwania faktyczny (z licznika) w milisekundach: [" + aktualneZadanie.s1CzasTrwaniaFaktyczny + "] i w formacie zegarowym: [" + aktualneZadanie.s1CzasTrwaniaFaktycznyS + "]\n";

		aktualneZadanie.s1CzasTotal = aktualneZadanie.s1CzasTrwaniaFaktyczny + aktualneZadanie.s1CzasPauz;
		aktualneZadanie.s1CzasTotalS = formatZSekundami(aktualneZadanie.s1CzasTotal) + ", " + aktualneZadanie.s1CzasTotal;


		
		aktualneZadanie.s1CzasPauzS = formatZSekundami(tempCzasPauz) + ", " + tempCzasPauz;
		
		przebiegZadaniaMeldunek += "  Xczas pauz: " + aktualneZadanie.s1CzasPauz + "\n";
		przebiegZadaniaMeldunek += "  XTOTALs1: " + "czas pauz: " + aktualneZadanie.s1CzasPauz + " + czas trwania z licznika: " + +aktualneZadanie.s1CzasTrwaniaFaktyczny + "  =  " + aktualneZadanie.s1CzasTotal + "\n";

		
		
		
		try {
			aktualneZadanie.s3CzasTotalS = aktualneZadanie.wyliczRecznie(aktualneZadanie.czasRozpoczecia, aktualneZadanie.czasZakonczenia);
			aktualneZadanie.s3CzasTotal = sparsuj(aktualneZadanie.s3CzasTotalS);
		
		} catch (ParseException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		przebiegZadaniaMeldunek += "  XCzasOdDos3: w milisekundach [" + aktualneZadanie.s3CzasTotal +"] i w formacie zegatowym: ["+ aktualneZadanie.s3CzasTotalS +"]\n";

		

		try {
			aktualneZadanie.s3CzasTotalS = aktualneZadanie.wyliczRecznie(aktualneZadanie.czasRozpoczecia, aktualneZadanie.czasZakonczenia);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		zamknijBiezace();
		tempCzasPauz = 0;

	}

	public void pauzeCounter() {
		/*
		 * pauzaOd = licznikBiezacy; System.out.println("Pauza od: "+pauzaOd);
		 */

		pauseTimeLicznika = System.currentTimeMillis();
		timer.stop();
		terminSpauzowania = simpleDateFormat.format(new Date());
		System.out.println("---czas spauzowania: " + terminSpauzowania + ", " + getText());

		przebiegZadaniaMeldunek += "---czas spauzowania: " + terminSpauzowania + ", " + getText() + "\n";

		aktualneZadanie.ilePauzZadania++;

		Timestamp timestamp = new Timestamp(System.currentTimeMillis());
		dataSpauzowania = new Date(timestamp.getTime());
	}

	public void unpauzeCounter() {
		if (running == false) {
			startTimeLicznika = System.currentTimeMillis();
		} else {
			startTimeLicznika = System.currentTimeMillis() - (pauseTimeLicznika - startTimeLicznika);
		}

		timer.start();
		running = true;

		Timestamp timestamp = new Timestamp(System.currentTimeMillis());

		dataOdpauzowania = new Date(timestamp.getTime());
		SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
		terminOdpauzowania = simpleDateFormat.format(new Date());
		System.out.println("---czas odpauzowania: " + terminOdpauzowania + ", " + getText());
		przebiegZadaniaMeldunek += "---czas odpauzowania: " + terminOdpauzowania + ", " + getText() + "\n";

		long czasTrwaniaPauzy = dataOdpauzowania.getTime() - dataSpauzowania.getTime();

		System.out.println("czas trwania tej pauzy, w milisekundach: " + czasTrwaniaPauzy);

		przebiegZadaniaMeldunek += "czas trwania tej pauzy, w milisekundach: " + czasTrwaniaPauzy + "\n";

		tempCzasPauz += czasTrwaniaPauzy;
		aktualneZadanie.s1CzasPauz = tempCzasPauz;
		System.out.println("!!! aktualneZadanie.s1CzasPauz: " + aktualneZadanie.s1CzasPauz);

		aktualneZadanie.s1CzasPauzS = formatZSekundami(tempCzasPauz) + ", " + tempCzasPauz;

		System.out.println("- łączny czas trwania pauz zsumowany, w milisekundach: " + aktualneZadanie.s1CzasPauz);
		przebiegZadaniaMeldunek += "- łączny czas trwania pauz zsumowany, w milisekundach: " + aktualneZadanie.s1CzasPauz + "\n";

	}

	public static double zaokraglijDoPolGodziny(long time) {

		final long hr = TimeUnit.MILLISECONDS.toHours(time);
		double total = (double) hr;

		final long min = TimeUnit.MILLISECONDS.toMinutes(time - TimeUnit.HOURS.toMillis(hr));
		final long sec = TimeUnit.MILLISECONDS.toSeconds(time - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));

		long calychMinut = 0;
		long min2 = min;

		if (sec > 30) {
			calychMinut = 1;
			min2 = min2 + calychMinut;
		}

		double polGodziny = 0;

		// 20 min = 0 h
		// 30 min = 0,5 h
		// 50 min = 1 h

		if (min2 >= 25 && min2 <= 45) {
			polGodziny = 0.5;
		}

		/*
		 * else if (min2 > 40 && min2 <=50) {
		 * 
		 * polGodziny = 0.75; }
		 */
		else if (min2 > 45) {
			polGodziny = 1;
		}

		double zaokraglone = total + polGodziny;
		return zaokraglone;
	}

	public static long sparsuj(String times) {
		long time = 0;

		/*
		 * 1000 = 1 second 60000 = 1 minute 3600000 = 1 hour
		 */

		String godzins = times.substring(0, 1);

		long godzin = Long.valueOf(times.substring(0, 2)).longValue();
		String minuts = times.substring(3, 5);
		long minut = Long.valueOf(times.substring(3, 5)).longValue();

		String sekunds = times.substring(6, 8);
		long sekund = Long.valueOf(times.substring(6, 8)).longValue();

		time = godzin * 3600000 + minut * 60000 + sekund * 1000;
		return time;
	}

	public static String formatZSekundamiStatic(final long time) {
		final long hr = TimeUnit.MILLISECONDS.toHours(time);
		final long min = TimeUnit.MILLISECONDS.toMinutes(time - TimeUnit.HOURS.toMillis(hr));
		final long sec = TimeUnit.MILLISECONDS.toSeconds(time - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
		return String.format("%02d:%02d:%02d", hr, min, sec);
	}

	public String formatZSekundami(final long time) {
		final long hr = TimeUnit.MILLISECONDS.toHours(time);
		final long min = TimeUnit.MILLISECONDS.toMinutes(time - TimeUnit.HOURS.toMillis(hr));
		final long sec = TimeUnit.MILLISECONDS.toSeconds(time - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
		return String.format("%02d:%02d:%02d", hr, min, sec);
	}

	// formatuj milisekundy na format licznikowy
	private static String formatZDziesiatymiSekundy(final long time) {
		final long hr = TimeUnit.MILLISECONDS.toHours(time);
		final long min = TimeUnit.MILLISECONDS.toMinutes(time - TimeUnit.HOURS.toMillis(hr));
		final long sec = TimeUnit.MILLISECONDS.toSeconds(time - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min));
		final long ms = TimeUnit.MILLISECONDS.toMillis(time - TimeUnit.HOURS.toMillis(hr) - TimeUnit.MINUTES.toMillis(min) - TimeUnit.SECONDS.toMillis(sec));
		return String.format("%02d:%02d:%02d.%01d", hr, min, sec, ms / 100);
	}

	public String toString() {
		return dataZadania + " " + s3CzasTotalS + " Zadanie " + iDZadania + " | " + czasRozpoczecia + "-" + czasZakonczenia + " | " + opis + " | " + s1CzasTrwaniaFaktycznyS + " | " + s1CzasTotalS + " | " + s1CzasPauzS;
	}

	public String wyliczCzasZadaniaDoRedmine() {
		String czasZadaniaDoRedmine = "";
		if (s1CzasTrwaniaFaktyczny != 0) {
			//System.out.println("!!! dla zadania istnieje czas faktyczny");
			czasZadaniaDoRedmine = s1CzasTrwaniaFaktycznyS;

		} else {
			//System.out.println("!!! dla zadania nie istnieje czas faktyczny - zostanie użyty s3CzasTotalS");
			czasZadaniaDoRedmine = s3CzasTotalS;
		}
		// System.out.println(toString() + "    " + czasZadaniaDoRedmine);
		return czasZadaniaDoRedmine;

	}

	public static String wyswietlZadaniaGrupowanePoDacie() {
		String info = "";
		String grupaZDnia = "";
		long sumaGodzinDnia = 0;

		long sumaGodzinOpisu = 0;

		if (wszystkieZadania.isEmpty()) {
			info = "Brak zadań";
		}

		else {
			// System.out.println(daty);
			for (int i = 0; i < daty.size(); i++) {
				info += daty.get(i).toString() + "\n";
				for (Zadanie z : wszystkieZadania) {
					if (z.dataZadania.equalsIgnoreCase(daty.get(i).toString())) {
						grupaZDnia += "Zadanie " + z.iDZadania + " | " + z.czasRozpoczecia + "-" + z.czasZakonczenia + " | " + z.opis + " | " + z.wyliczCzasZadaniaDoRedmine() + "\n";
						sumaGodzinDnia += sparsuj(z.wyliczCzasZadaniaDoRedmine());
					}
				}
				info += grupaZDnia;
				info += wyliczSumeDlaOpisu(daty.get(i).toString());
				info += "SUMA DLA " + daty.get(i).toString() + ": " + formatZSekundamiStatic(sumaGodzinDnia) + " | Redmine: " + zaokraglijDoPolGodziny(sumaGodzinDnia) + "\n" + "\n";
				System.out.println("SUMA DLA " + daty.get(i).toString() + ": " + formatZSekundamiStatic(sumaGodzinDnia) + " | Redmine: " + zaokraglijDoPolGodziny(sumaGodzinDnia) + "\n");

				grupaZDnia = "";
				sumaGodzinDnia = 0;
			}
		}
		return info;
	}
/*	
	public void zaktualizujSumeDlaOpisu() {
		wyliczSumeDlaOpisu(this.dataZadania);
	}
*/
	public static String wyliczSumeDlaOpisu(String dzien) {
		String info = "Suma dla " + dzien + "\n";
		long sumaGodzinOpisu = 0;
		for (int i = 0; i < opisy.size(); i++) {
			for (Zadanie z : wszystkieZadania) {
				if (z.dataZadania.equalsIgnoreCase(dzien)) {
					if (z.opis.equalsIgnoreCase(opisy.get(i).toString())) {
						sumaGodzinOpisu += sparsuj(z.wyliczCzasZadaniaDoRedmine());
					}
				}
			}

			if (sumaGodzinOpisu != 0) {
				info += "- " + opisy.get(i).toString() + ": " + formatZSekundamiStatic(sumaGodzinOpisu) + " | Redmine: " + zaokraglijDoPolGodziny(sumaGodzinOpisu) + "\n";
			}
			sumaGodzinOpisu = 0;
		}

		System.out.println(info);
		return info;
	}

	public static String wyswietlZadaniaDzisiejsze() {
		String info = "";
		if (wszystkieZadania.isEmpty()) {
			info += Program.instrukcja();
		} else {
			aktualnaData = formatyyyyMMdd.format(new Date());
			for (Zadanie z : wszystkieZadania) {
				if (z.dataZadania.equalsIgnoreCase(Zadanie.aktualnaData)) {
					info += z.toString() + "\n";
				}
			}
		}
		return info;
	}

	public String statusUpdate() {
		String status = "";
		String IDZadania = "";
		String przerw = "";
		String zadan = "";
		if ((aktualneZadanie != null) && (ilePauzZadania > 0)) {
			przerw = " Przerw: " + ilePauzZadania;
		}

		int ileWykonanychDzis = 0;
		for (Zadanie z : wszystkieZadania) {
			if (z.dataZadania.equalsIgnoreCase(aktualnaData) && (!z.s1CzasTrwaniaFaktycznyS.equalsIgnoreCase("00:00:00"))) {
				ileWykonanychDzis++;
			}
		}
		zadan = " Wykonanych dziś zadań: " + ileWykonanychDzis;
		aktualnaData = formatyyyyMMdd.format(new Date());
		status = "Dziś mamy: " + aktualnaData + IDZadania + przerw + zadan;
		return status;
	}

	/* ODTWARZANIE, BACKUP, DODAWANIE RĘCZNIE */

	public static Zadanie dodajRecznieZadanie(String dataMoja, int numer, String nowyOpis, String otwarcie, String zamkniecie) throws ParseException {
		Zadanie noweZadanie = new Zadanie();
		Zadanie.wszystkieZadania.add(noweZadanie);

		noweZadanie.iDZadania = numer;
		noweZadanie.dataZadania = dataMoja;
		noweZadanie.czasRozpoczecia = otwarcie;
		noweZadanie.czasZakonczenia = zamkniecie;
		noweZadanie.opis = nowyOpis;
		if (!daty.contains(noweZadanie.dataZadania)) {
			daty.add(noweZadanie.dataZadania);
		}

		if (!opisy.contains(noweZadanie.opis)) {
			opisy.add(noweZadanie.opis);
		}
		noweZadanie.s3CzasTotalS = noweZadanie.wyliczRecznie(otwarcie, zamkniecie);
		noweZadanie.s1CzasPauzS = "n.d.";
		noweZadanie.s1CzasTrwaniaFaktycznyS = "n.d.";
		noweZadanie.ilePauzZadaniaS = "n.d.";
		noweZadanie.s1CzasTotalS = "n.d.";
		return noweZadanie;
	}

	public void zmienDateZadania(int numer, String dataMoja) {
		for (Zadanie z : wszystkieZadania) {
			if ((z.iDZadania == numer) && z.dataZadania.equalsIgnoreCase(dataMoja)) {
				System.out.println(z.toString());
				System.out.println("Zmiana daty zadania nr " + z.iDZadania);
				System.out.println("Z: " + z.dataZadania + " na: " + dataMoja);
				z.dataZadania = dataMoja;
				System.out.println(z.toString());
			}
		}
	}

	public void zmienOpisZadania(int numer, String dataMoja, String nowyOpis) {
		for (Zadanie z : Zadanie.wszystkieZadania) {
			if ((z.iDZadania == numer) && z.dataZadania.equalsIgnoreCase(dataMoja)) {
				System.out.println(z.toString());
				System.out.println("Zmiana opisu zadania nr " + z.iDZadania + " z dnia " + z.dataZadania);
				System.out.println("Z: " + z.opis + " na: " + nowyOpis);
				z.opis = nowyOpis;
				System.out.println(z.toString());
			}
		}
	}

	public String wyliczRecznie(String otwarcie, String zamkniecie) throws ParseException {
		long temp = s3CzasTotalSZeSparsowanychCzasow(otwarcie, zamkniecie);
		String tempString = formatZSekundami(temp);
		return tempString;
	}

	public long s3CzasTotalSZeSparsowanychCzasow(String czas1, String czas2) {
		Date start = null;
		Date end = null;
		try {
			start = simpleDateFormat.parse(czas1);
			end = simpleDateFormat.parse(czas2);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return (end.getTime() - start.getTime());
	}

	public String wyswietlPrzebiegZadaniaMeldunek() {
		return przebiegZadaniaMeldunek;
	}

	/* EKSTENSJA */

	/* do ekstencji = autocounter get */
	public static int getAutoCounter() {
		return autoCounter;
	}

	/* do ekstencji = autocounter set */
	public static void setAutoCounter(int autoCounter) {
		autoCounter = autoCounter;
	}

	public static void pokazEkstensje() throws FileNotFoundException, IOException, ClassNotFoundException {
		System.out.println("----------------------");
		System.out.println("Ekstensja klasy: " + Zadanie.class);
		for (Zadanie z : wszystkieZadania) {
			String spacja = "";
			if (z.iDZadania < 10) {
				spacja = " ";
			}
			System.out.println(spacja + z.toString());
		}
	}

	public static void wczytajEkstensje(ObjectInputStream in) throws FileNotFoundException, IOException, ClassNotFoundException {
		wszystkieZadania = (ArrayList<Zadanie>) in.readObject();
		int numer = in.readInt();
		setAutoCounter(numer);
	}

	public static void zapiszEkstensje(ObjectOutputStream out) throws IOException {
		out.writeObject(wszystkieZadania);
		out.writeInt(getAutoCounter());
	}


}